home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #2 / Amiga Plus CD - 2004 - No. 02.iso / AmigaPlus / Tools / Development / AmigaTalk / general / AspectAdaptor.st < prev    next >
Encoding:
Text File  |  2004-01-31  |  5.6 KB  |  144 lines

  1. " ----------------------------------------------------------------------
  2.   Class AspectAdaptor provides the appearance of a ValueHolder, but 
  3.   redirects the value and value: methods to the target by sending 
  4.   getSelector and putSelector, respectively.  The putSelector is assumed 
  5.   to take a single argument which is the argument provided to value:.
  6.  
  7.   When there is no target, the value is always nil; setValue: is a no-op; 
  8.   and value: only notifies the dependents.
  9.  
  10.   Instance Variables:
  11.      getSelector   <Symbol>  0-arg message selector
  12.      putSelector   <Symbol>  1-arg message selector
  13.      aspect        <Symbol | nil> aspect for which the adaptor is willing to 
  14.                               field updates.  If nil, use the getSelector instead
  15.   Object Reference:
  16.   An AspectAdaptor is widely used in applications, to get and set an 
  17.   embedded value.  While a ValueHolder typically manages a value held by 
  18.   an application model, an AspectedAdaptor typically manages a value held 
  19.   by a domain model, which itself is held by the application model.  The 
  20.   domain model is the adaptor's subject, and the adaptor must be equipped 
  21.   with messages (getSelector and putSelector) for accessing the desired value 
  22.   in the subject.  See ProtocolAdaptor (the parent class) for a descriptive 
  23.   example. 
  24.   
  25.   An AspectAdaptor is typically created by sending a #subject: message to 
  26.   this class, with the domain model as the argument.  The getSelector and 
  27.   putSelector are typically the same message (with a colon, in the case of 
  28.   the putSelector) and can be set via #forAspect:.  When the getSelector and 
  29.   putSelector are dissimilar, use #accessWith:assignWith: to set them. 
  30.   
  31.   An AspectAdaptor can manage a value that is embedded multiple levels within 
  32.   the subject, via an access path.  It can also be told to withhold its 
  33.   update messages to avoid duplicating those sent by its subject.  See 
  34.   ProtocolAdaptor for a fuller discussion of these abilities. 
  35.   -----------------------------------------------------------------------
  36. "
  37. Class AspectAdaptor :ProtocolAdaptor
  38. ! getSelector putSelector aspect !
  39. [
  40.    accessWith: getSymbol assignWith: putSymbol
  41.      " Create a new AspectAdaptor and initialize the getSelector and putSelector
  42.      * with getSymbol and putSymbol, respectively. The subject or subjectChannel
  43.      * and whether the subject sends updates must be initialized separately.
  44.      "
  45.      ^ self new assignAccessWith: getSymbol assignWith: putSymbol
  46. |
  47.    accessWith: getSymbol assignWith: putSymbol accessPath: aSequencableCollection
  48.      "Create a new AspectAdaptor and initialize the getSelector and putSelector
  49.      * with getSymbol and putSymbol, respectively. The subject or subjectChannel
  50.      * and whether the subject sends updates must be initialized separately.
  51.      "
  52.  
  53.      ^ (self accessPath: aSequencableCollection) 
  54.              accessWith: getSymbol 
  55.              assignWith: putSymbol
  56. |
  57.    forAspect: anAspectSymbol
  58.      " Create a new AspectAdaptor and initialize the getSelector and putSelector
  59.      * based on anAspectSymbol and the symbol with a colon appended.
  60.      * The subject or subjectChannel and whether the subject sends updates must
  61.      * be initialized separately.
  62.      "
  63.      ^ self new setAspect: anAspectSymbol
  64. |
  65.    forAspect: anAspectSymbol accessPath: aSequencableCollection
  66.      "Create a new AspectAdaptor and initialize the getSelector and putSelector
  67.      * based on anAspectSymbol and the symbol with a colon appended.
  68.      * The subject or subjectChannel and whether the subject sends updates must
  69.      * be initialized separately.
  70.      "
  71.  
  72.      ^ (self accessPath: aSequencableCollection) forAspect: anAspectSymbol
  73. |
  74.    assignAccessWith: getSymbol assignWith: putSymbol
  75.      " Set or change the symbols used to access the subject. "
  76.  
  77.      self accessWith: getSymbol assignWith: putSymbol aspect: nil
  78. |
  79.    accessWith: getSymbol assignWith: putSymbol aspect: aspectSymbol
  80.      " Set or change the symbols used to access the subject. "
  81.  
  82.      getSelector <- getSymbol.
  83.      putSelector <- putSymbol.
  84.      aspect      <- aspectSymbol
  85. |
  86.    forAspect
  87.      " Answer the aspect we're adapting. "
  88.  
  89.      ^ aspect == nil
  90.          ifTrue: [getSelector]
  91.         ifFalse: [aspect]
  92. |
  93.    setAspect: anAspectSymbol
  94.      "Set or change the symbols used to access the subject."
  95.  
  96.      self accessWith: anAspectSymbol assignWith: (anAspectSymbol, ':') asSymbol
  97. |
  98.    initialize
  99.  
  100.      super initialize.
  101.      self accessWith: #value assignWith: #value:
  102. |
  103.    setValueUsingTarget: anObject to: newValue
  104.      " Set the value of anObject by sending the receiver's 
  105.      * store (put) selector to the anObject with argument newValue.
  106.      "
  107.  
  108.      (anObject == nil)
  109.         ifFalse: [anObject perform: putSelector with: newValue]
  110. |
  111.    valueUsingTarget: anObject
  112.      " Answer the value returned by sending the receiver's retrieval 
  113.      * (get)  selector to anObject
  114.      "
  115.  
  116.       (anObject == nil)
  117.          ifFalse:   [ ^ anObject perform: getSelector]
  118.           ifTrue:   [ ^ nil]
  119. |
  120.    update: anAspect with: parameter from: sender
  121.      " Propagate change if the sender is the receiver's subject 
  122.      * and anAspect is the receiver's aspect.
  123.      "
  124.      (sender == super subject and: [anAspect == self forAspect])
  125.          ifTrue: [super dependents update: #value with: parameter from: self]
  126.         ifFalse: [super update: anAspect with: parameter from: sender]
  127. |
  128.    printOn: aStream
  129.  
  130.      aStream print: self class.
  131.      
  132.      aStream nextPut: $(.
  133.      
  134.      self target printOn: aStream.
  135.      
  136.      aStream space.
  137.      
  138.      self printPathOn: aStream.
  139.      
  140.      aStream nextPutAll: getSelector.
  141.      
  142.      aStream nextPut: $).
  143. ]
  144.